/**
 * This file is Copyright © 2008 Software Craftsmen Limited. All Rights Reserved.
 */
package com.softwarecraftsmen.orogeny.filing.findSubdirectoriesFilters;

import com.softwarecraftsmen.orogeny.filing.AbsoluteDirectory;
import com.softwarecraftsmen.orogeny.filing.RelativeDirectory;
import org.jetbrains.annotations.NotNull;

public abstract class AbstractFindSubdirectoriesFilter implements FindSubdirectoriesFilter
{
	@NotNull
	public static final FindSubdirectoriesFilter AllSubdirectories = new AbstractFindSubdirectoriesFilter()
	{
		public boolean include(final @NotNull AbsoluteDirectory root, final @NotNull RelativeDirectory relativeDirectory)
		{
			return true;
		}

		@NotNull
		public String toString()
		{
			return "AllSubdirectories";
		}
	};
	
	@NotNull
	public static final FindSubdirectoriesFilter HiddenSubdirectoryExcluding = new AbstractFindSubdirectoriesFilter()
	{
		public boolean include(final @NotNull AbsoluteDirectory root, final @NotNull RelativeDirectory relativeDirectory)
		{
			return relativeDirectory.anyFolderIsHidden(root);
		}

		@NotNull
		public String toString()
		{
			return "HiddenSubdirectoryExcluding";
		}
	};

	@NotNull
	public static final FindSubdirectoriesFilter AllSubdirectoriesExcludingHiddenFolders = AllSubdirectories.excludeHiddenFolders();

	@NotNull
	public static final FindSubdirectoriesFilter NoSubdirectories = AllSubdirectories.not();

	@NotNull
	public final FindSubdirectoriesFilter exclude(final @NotNull FindSubdirectoriesFilter exclude)
	{
		return and(exclude.not());
	}

	@Override
	public final boolean exclude(final @NotNull AbsoluteDirectory root, final @NotNull RelativeDirectory relativeDirectory)
	{
		return !include(root, relativeDirectory);
	}

	@NotNull
	public final FindSubdirectoriesFilter and(final @NotNull FindSubdirectoriesFilter that)
	{
		return new AbstractFindSubdirectoriesFilter()
		{
			public boolean include(final @NotNull AbsoluteDirectory root, final @NotNull RelativeDirectory relativeDirectory)
			{
				return AbstractFindSubdirectoriesFilter.this.include(root, relativeDirectory) && that.include(root, relativeDirectory);
			}

			@NotNull
			public String toString()
			{
				return AbstractFindSubdirectoriesFilter.this.toString() + " and ( " + that.toString() + " )";
			}
		};
	}

	@NotNull
	public final FindSubdirectoriesFilter or(final @NotNull FindSubdirectoriesFilter that)
	{
		return new AbstractFindSubdirectoriesFilter()
		{
			public boolean include(final @NotNull AbsoluteDirectory root, final @NotNull RelativeDirectory relativeDirectory)
			{
				return AbstractFindSubdirectoriesFilter.this.include(root, relativeDirectory) || that.include(root, relativeDirectory);
			}

			@NotNull
			public String toString()
			{
				return AbstractFindSubdirectoriesFilter.this.toString() + " or ( " + that.toString() + " )";
			}
		};
	}

	@NotNull
	public final FindSubdirectoriesFilter not()
	{
		return new AbstractFindSubdirectoriesFilter()
		{
			public boolean include(final @NotNull AbsoluteDirectory root, final @NotNull RelativeDirectory relativeDirectory)
			{
				return !AbstractFindSubdirectoriesFilter.this.include(root, relativeDirectory);
			}

			@NotNull
			public String toString()
			{
				return "not( " + AbstractFindSubdirectoriesFilter.this.toString() + " )";
			}
		};
	}

	@NotNull
	public final FindSubdirectoriesFilter excludeHiddenFolders()
	{
		return and(HiddenSubdirectoryExcluding);
	}

	@NotNull
	public String toString()
	{
		return getClass().getSimpleName();
	}
}
